home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Textfiles / zines / Phrack / Phrack Issue 53.sit / 53 / P53-13 < prev    next >
Text File  |  1998-07-08  |  24KB  |  661 lines

  1. ---[  Phrack Magazine   Volume 8, Issue 53 July 8, 1998, article 13 of 15
  2.  
  3.  
  4. -------------------------[  Designing and Attacking Port Scan Detection Tools
  5.  
  6.  
  7. --------[  solar designer <solar@false.com>
  8.                                                          
  9.  
  10. ----[  Introduction
  11.  
  12. The purpose of this article is to show potential problems with intrusion
  13. detection systems (IDS), concentrating on one simple attack: port scans.
  14.  
  15. This lets me cover all components of such a simplified IDS.  Also, unlike
  16. the great SNI paper (http://www.secnet.com/papers/IDS.PS), this article
  17. is not limited to network-based tools.  In fact, the simple and hopefully
  18. reliable example port scan detection tool ("scanlogd") that you'll find
  19. at the end is host-based.
  20.  
  21.  
  22. ----[  What Can We Detect?
  23.  
  24. A port scan involves an attacker trying many destination ports, usually
  25. including some that turn out not to be listening.  One "signature" that
  26. could be used for detecting port scans is "several packets to different
  27. destination ports from the same source address within a short period of
  28. time".  Another such signature could be "SYN to a non-listening port".
  29. Obviously, there are many other ways to detect port scans, up to dumping
  30. all the packet headers to a file and analyzing them manually (ouch).
  31.  
  32. All of these different methods have their own advantages and disadvantages,
  33. resulting in different numbers of "false positives" and "false negatives".
  34. Now, let me show that, for this particular attack type, it is always possible
  35. for an attacker to make her attack either very unlikely to be noticed, or very
  36. unlikely to be traced to its real origin, while still being able to obtain
  37. the port number information.
  38.  
  39. To obscure the attack, an attacker could do the scan very slowly.  Unless the
  40. target system is normally idle (in which case one packet to a non-listening
  41. port is enough for the admin to notice, not a likely real world situation),
  42. it is possible to make the delay between ports large enough for this to be
  43. likely not recognized as a scan.
  44.  
  45. A way to hide the origin of a scan, while still receiving the information,
  46. is to send a large amount (say, 999) of spoofed "port scans", and only on
  47. scan from the real source address.  Even if all the scans (1000 of them) are
  48. detected and logged, there's no way to tell which of the source addresses is
  49. real.  All we can tell is that we've been port scanned.
  50.  
  51. Note that, while these attacks are possible, they obviously require more
  52. resources from the attacker to perform.  Some attackers will likely choose
  53. not to use such complicated and/or slow attacks, and others will have to
  54. pay with their time.  This alone is enough reason to still detect at least
  55. some port scans (the ones that are detectable).
  56.  
  57. The possibility of such attacks means that our goal is not to detect all
  58. port scans (which is impossible), but instead, in my opinion, to detect
  59. as many port scan kinds as possible while still being reliable enough.
  60.  
  61.  
  62. ----[  What Information Can We Trust?
  63.  
  64. Obviously, the source address can be spoofed, so we can't trust it unless
  65. other evidence is available.  However, port scanners sometimes leak extra
  66. information that can be used to tell something about the real origin of a
  67. spoofed port scan.
  68.  
  69. For example, if the packets we receive have an IP TTL of 255 at our end, we
  70. know for sure that they're being sent from our local network regardless of
  71. what the source address field says.  However, if TTL is 250, we can only tell
  72. that the attacker was no more than 5 hops away, we can't tell how far exactly
  73. she was for sure.
  74.  
  75. Starting TTL and source port number(s) can also give us a hint of what
  76. port scanner type (for "stealth" scans) or operating system (for full TCP
  77. connection scans) is used by the attacker.  We can never be sure though.
  78. For example, nmap sets TTL to 255 and source port to 49724, while Linux
  79. kernel sets TTL to 64.
  80.  
  81.  
  82. ----[  Information Source (E-box) Choice
  83.  
  84. For detecting TCP port scans, including "stealth" ones, we need access
  85. to raw IP and TCP packet headers.
  86.  
  87. In a network-based IDS, we would use promiscuous mode for obtaining the
  88. raw packets.  This has all the problems described in the SNI paper: both
  89. false positives and false negatives are possible.  However, sometimes
  90. this might be acceptable for this attack type since it is impossible to
  91. detect all port scans anyway.
  92.  
  93. For a host-based IDS, there are two major ways of obtaining the packets:
  94. reading from a raw TCP or IP socket, or getting the data directly inside
  95. the kernel (via a loadable module or a kernel patch).
  96.  
  97. When using a raw TCP socket, most of the problems pointed out by SNI do
  98. not apply: we are only getting the packets recognized by our own kernel.
  99. However, this is still passive analysis (we might miss packets) and a
  100. fail-open system.  While probably acceptable for port scans only, this
  101. is not a good design if we later choose to detect other attacks.  If we
  102. used a raw IP socket instead (some systems don't have raw TCP sockets),
  103. we would have more of the "SNI problems" again.  Anyway, in my example
  104. code, I'm using a raw TCP socket.
  105.  
  106. The most reliable IDS is one with some support from the target systems
  107. kernel.  This has access to all the required information, and can even be
  108. fail-close.  The obvious disadvantage is that kernel modules and patches
  109. aren't very portable.
  110.  
  111.  
  112. ----[  Attack Signature (A-box) Choice
  113.  
  114. It has already been mentioned above that different signatures can be
  115. used to detect port scans; they differ by numbers of false positives
  116. and false negatives.  The attack signature that we choose should keep
  117. false positives as low as possible while still keeping false negatives
  118. reasonably low.  It is however not obvious what to consider reasonable.
  119. In my opinion, this should depend on the severity of the attack we're
  120. detecting (the cost of a false negative), and on the actions taken for
  121. a detected attack (the cost of a false positive).  Both of these costs
  122. can differ from site to site, so an IDS should be user-tunable.
  123.  
  124. For scanlogd, I'm using the following attack signature: "at least COUNT
  125. ports need to be scanned from the same source address, with no longer
  126. than DELAY ticks between ports".  Both COUNT and DELAY are configurable.
  127. A TCP port is considered to be scanned when receiving a packet without
  128. the ACK bit set.
  129.  
  130.  
  131. ----[  Logging the Results (D-box)
  132.  
  133. Regardless of where we write our logs (a disk file, a remote system, or
  134. maybe even a printer), our space is limited.  When storage is full, results
  135. will get lost.  Most likely, either the logging stops, or old entries get
  136. replaced with newer ones.
  137.  
  138. An obvious attack is to fill up the logs with unimportant information,
  139. and then do the real attack with the IDS effectively disabled.  For the
  140. port scans example, spoofed "port scans" could be used to fill up the
  141. logs, and the real attack could be a real port scan, possibly followed
  142. by a breakin.  This example shows how a badly coded port scan detection
  143. tool could be used to avoid logging of the breakin attempt, which would
  144. get logged if the tool wasn't running.
  145.  
  146. One solution for this problem would be to put rate limits (say, no more
  147. than 5 messages per 20 seconds) on every attack type separately, and,
  148. when the limit is reached, log this fact, and temporarily stop logging
  149. of attacks of this type.  For attack types that can't be spoofed, such
  150. limits could be put per source address instead.  Since port scans can be
  151. spoofed, this still lets an attacker not reveal her real address, but
  152. this doesn't let her hide another attack type this way, like she could
  153. do if we didn't implement the rate limits... that's life.  This is what
  154. I implemented in scanlogd.
  155.  
  156. Another solution, which has similar advantages and disadvantages, is to
  157. allocate space for messages from every attack type separately.  Both of
  158. these solutions can be implemented simultaneously.
  159.  
  160.  
  161. ----[  What To Do About Port Scans? (R-box)
  162.  
  163. Some IDS are capable of responding to attacks they detect.  The actions
  164. are usually directed to prevent further attacks and/or to obtain extra
  165. information about the attacker.  Unfortunately, these features can often
  166. be abused by a smart attacker.
  167.  
  168. A typical action is to block the attacking host (re-configuring access
  169. lists of the firewall, or similar).  This leads to an obvious Denial of
  170. Service (DoS) vulnerability if the attack we're detecting is spoofable
  171. (like a port scan is).  It is probably less obvious that this leads to DoS
  172. vulnerabilities for non-spoofable attack types, too.  That's because IP
  173. addresses are sometimes shared between many people; this is the case for
  174. ISP shell servers and dynamic dialup pools.
  175.  
  176. There are also a few implementation problems with this approach: firewall
  177. access lists, routing tables, etc... are all of a limited size.  Also, even
  178. before the limit is reached, there are CPU usage issues.  If an IDS is not
  179. aware of these issues, this can lead to DoS of the entire network (say,
  180. if the firewall goes down).
  181.  
  182. In my opinion, there're only very few cases in which such an action might
  183. be justified.  Port scans are definitely not among those.
  184.  
  185. Another common action is to connect back to the attacking host to obtain
  186. extra information.  For spoofable attacks, we might end up being used in
  187. attacking a third-party.  We'd better not do anything for such attacks,
  188. including port scans.
  189.  
  190. However, for non-spoofable attacks, this might be worth implementing in
  191. some cases, with a lot of precautions.  Mainly, we should be careful not
  192. to consume too many resources, including bandwidth (should limit request
  193. rate regardless of the attack rate, and limit the data size), CPU time,
  194. and memory (should have a timeout, and limit the number of requests that
  195. we do at a time).  Obviously, this means that an attacker can still make
  196. some of the requests fail, but there's nothing we can do here.
  197.  
  198. See ftp://ftp.win.tue.nl/pub/security/murphy.ps.gz for an example of the
  199. issues involved.  This paper by Wietse Venema details similar vulnerabilities
  200. in older versions of his famous TCP wrapper package.
  201.  
  202. For these reasons, scanlogd doesn't do anything but log port scans.  You
  203. should probably take action yourself.  What exactly you do is a matter
  204. of taste; I personally only check my larger logs (that I'm not checking
  205. normally) for activity near the port scan time.
  206.  
  207.  
  208. ----[  Data Structures and Algorithm Choice
  209.  
  210. When choosing a sorting or data lookup algorithm to be used for a normal
  211. application, people are usually optimizing the typical case.  However, for
  212. IDS the worst case scenario should always be considered: an attacker can
  213. supply our IDS with whatever data she likes.  If the IDS is fail-open, she
  214. would then be able to bypass it, and if it's fail-close, she could cause
  215. a DoS for the entire protected system.
  216.  
  217. Let me illustrate this by an example.  In scanlogd, I'm using a hash table
  218. to lookup source addresses.  This works very well for the typical case as
  219. long as the hash table is large enough (since the number of addresses we
  220. keep is limited anyway).  The average lookup time is better than that of a
  221. binary search.  However, an attacker can choose her addresses (most likely
  222. spoofed) to cause hash collisions, effectively replacing the hash table
  223. lookup with a linear search.  Depending on how many entries we keep, this
  224. might make scanlogd not be able to pick new packets up in time.  This will
  225. also always take more CPU time from other processes in a host-based IDS
  226. like scanlogd.
  227.  
  228. I've solved this problem by limiting the number of hash collisions, and
  229. discarding the oldest entry with the same hash value when the limit is
  230. reached.  This is acceptable for port scans (remember, we can't detect all
  231. scans anyway), but might not be acceptable for detecting other attacks.
  232. If we were going to support some other attack type also, we would have to
  233. switch to a different algorithm instead, like a binary search.
  234.  
  235. If we're using a memory manager (such as malloc(3) and free(3) from our
  236. libc), an attacker might be able to exploit its weaknesses in a similar
  237. way.  This might include CPU usage issues and memory leaks because of not
  238. being able to do garbage collection efficiently enough.  A reliable IDS
  239. should have its very own memory manager (the one in libc can differ from
  240. system to system), and be extremely careful with its memory allocations.
  241. For a tool as simple as scanlogd is, I simply decided not to allocate any
  242. memory dynamically at all.
  243.  
  244. It is probably worth mentioning that similar issues also apply to things
  245. like operating system kernels.  For example, hash tables are widely used
  246. there for looking up active connections, listening ports, etc.  There're
  247. usually other limits which make these not really dangerous though, but
  248. more research might be needed.
  249.  
  250.  
  251. ----[  IDS and Other Processes
  252.  
  253. For network-based IDS that are installed on a general-purpose operating
  254. system, and for all host-based IDS, there's some interaction of the IDS
  255. with the rest of the system, including other processes and the kernel.
  256.  
  257. Some DoS vulnerabilities in the operating system might allow an attacker
  258. to disable the IDS (of course, only if it is fail-open) without it ever
  259. noticing.  This can be done via vulnerabilities in both the kernel (like
  260. "teardrop") and in other processes (like having a UDP service enabled in
  261. inetd without a connection count limit and any resource limits).
  262.  
  263. Similarly, a poorly coded host-based IDS can be used for DoS attacks on
  264. other processes of the "protected" system.
  265.  
  266.  
  267. ----[  Example Code
  268.  
  269. Finally, here you get scanlogd for Linux.  It may compile on other systems
  270. too, but will likely not work because of the lack of raw TCP sockets.  For
  271. future versions see http://www.false.com/security/scanlogd/.
  272.  
  273. NOTE THAT SOURCE ADDRESSES REPORTED CAN BE SPOOFED, DON'T TAKE ANY ACTION
  274. AGAINST THE ATTACKER UNLESS OTHER EVIDENCE IS AVAILABLE.
  275.  
  276. <++> Scanlogd/scanlogd.c
  277. /*
  278.  * Linux scanlogd v1.0 by Solar Designer.  You're allowed to do whatever you
  279.  * like with this software (including re-distribution in any form, with or
  280.  * without modification), provided that credit is given where it is due, and
  281.  * any modified versions are marked as such.  There's absolutely no warranty.
  282.  */
  283.  
  284. #include <stdio.h>
  285. #include <unistd.h>
  286. #include <signal.h>
  287. #include <string.h>
  288. #include <ctype.h>
  289. #include <time.h>
  290. #include <syslog.h>
  291. #include <sys/times.h>
  292. #include <sys/types.h>
  293. #include <sys/socket.h>
  294. #include <netinet/in_systm.h>
  295. #include <netinet/in.h>
  296. #if (linux)
  297. #define __BSD_SOURCE
  298. #endif
  299. #include <netinet/ip.h>
  300. #include <netinet/tcp.h>
  301. #include <arpa/inet.h>
  302.  
  303. /*
  304.  * Port scan detection thresholds: at least COUNT ports need to be scanned
  305.  * from the same source, with no longer than DELAY ticks between ports.
  306.  */
  307. #define SCAN_COUNT_THRESHOLD        10
  308. #define SCAN_DELAY_THRESHOLD        (CLK_TCK * 5)
  309.  
  310. /*
  311.  * Log flood detection thresholds: temporarily stop logging if more than
  312.  * COUNT port scans are detected with no longer than DELAY between them.
  313.  */
  314. #define LOG_COUNT_THRESHOLD        5
  315. #define LOG_DELAY_THRESHOLD        (CLK_TCK * 20)
  316.  
  317. /*
  318.  * You might want to adjust these for using your tiny append-only log file.
  319.  */
  320. #define SYSLOG_IDENT            "scanlogd"
  321. #define SYSLOG_FACILITY            LOG_DAEMON
  322. #define SYSLOG_LEVEL            LOG_ALERT
  323.  
  324. /*
  325.  * Keep track of up to LIST_SIZE source addresses, using a hash table of
  326.  * HASH_SIZE entries for faster lookups, but limiting hash collisions to
  327.  * HASH_MAX source addresses per the same hash value.
  328.  */
  329. #define LIST_SIZE            0x400
  330. #define HASH_LOG            11
  331. #define HASH_SIZE            (1 << HASH_LOG)
  332. #define HASH_MAX            0x10
  333.  
  334. /*
  335.  * Packet header as read from a raw TCP socket. In reality, the TCP header
  336.  * can be at a different offset; this is just to get the total size right.
  337.  */
  338. struct header {
  339.     struct ip ip;
  340.     struct tcphdr tcp;
  341.     char space[60 - sizeof(struct ip)];
  342. };
  343.  
  344. /*
  345.  * Information we keep per each source address.
  346.  */
  347. struct host {
  348.     struct host *next;        /* Next entry with the same hash */
  349.     clock_t timestamp;        /* Last update time */
  350.     time_t start;            /* Entry creation time */
  351.     struct in_addr saddr, daddr;    /* Source and destination addresses */
  352.     unsigned short sport;        /* Source port, if fixed */
  353.     int count;            /* Number of ports in the list */
  354.     unsigned short ports[SCAN_COUNT_THRESHOLD - 1];    /* List of ports */
  355.     unsigned char flags_or;        /* TCP flags OR mask */
  356.     unsigned char flags_and;    /* TCP flags AND mask */
  357.     unsigned char ttl;        /* TTL, if fixed */
  358. };
  359.  
  360. /*
  361.  * State information.
  362.  */
  363. struct {
  364.     struct host list[LIST_SIZE];    /* List of source addresses */
  365.     struct host *hash[HASH_SIZE];    /* Hash: pointers into the list */
  366.     int index;            /* Oldest entry to be replaced */
  367. } state;
  368.  
  369. /*
  370.  * Convert an IP address into a hash table index.
  371.  */
  372. int hashfunc(struct in_addr addr)
  373. {
  374.     unsigned int value;
  375.     int hash;
  376.  
  377.     value = addr.s_addr;
  378.     hash = 0;
  379.     do {
  380.         hash ^= value;
  381.     } while ((value >>= HASH_LOG));
  382.  
  383.     return hash & (HASH_SIZE - 1);
  384. }
  385.  
  386. /*
  387.  * Log this port scan.
  388.  */
  389. void do_log(struct host *info)
  390. {
  391.     char s_saddr[32];
  392.     char s_daddr[32 + 8 * SCAN_COUNT_THRESHOLD];
  393.     char s_flags[8];
  394.     char s_ttl[16];
  395.     char s_time[32];
  396.     int index, size;
  397.     unsigned char mask;
  398.  
  399. /* Source address and port number, if fixed */
  400.     snprintf(s_saddr, sizeof(s_saddr),
  401.         info->sport ? "%s:%u" : "%s",
  402.         inet_ntoa(info->saddr),
  403.         (unsigned int)ntohs(info->sport));
  404.  
  405. /* Destination address, if fixed */
  406.     size = snprintf(s_daddr, sizeof(s_daddr),
  407.         info->daddr.s_addr ? "%s ports " : "ports ",
  408.         inet_ntoa(info->daddr));
  409.  
  410. /* Scanned port numbers */
  411.     for (index = 0; index < info->count; index++)
  412.         size += snprintf(s_daddr + size, sizeof(s_daddr) - size,
  413.             "%u, ", (unsigned int)ntohs(info->ports[index]));
  414.  
  415. /* TCP flags: lowercase letters for "always clear", uppercase for "always
  416.  * set", and question marks for "sometimes set". */
  417.     for (index = 0; index < 6; index++) {
  418.         mask = 1 << index;
  419.         if ((info->flags_or & mask) == (info->flags_and & mask)) {
  420.             s_flags[index] = "fsrpau"[index];
  421.             if (info->flags_or & mask)
  422.                 s_flags[index] = toupper(s_flags[index]);
  423.         } else
  424.             s_flags[index] = '?';
  425.     }
  426.     s_flags[index] = 0;
  427.  
  428. /* TTL, if fixed */
  429.     snprintf(s_ttl, sizeof(s_ttl), info->ttl ? ", TTL %u" : "",
  430.         (unsigned int)info->ttl);
  431.  
  432. /* Scan start time */
  433.     strftime(s_time, sizeof(s_time), "%X", localtime(&info->start));
  434.  
  435. /* Log it all */
  436.     syslog(SYSLOG_LEVEL,
  437.         "From %s to %s..., flags %s%s, started at %s",
  438.         s_saddr, s_daddr, s_flags, s_ttl, s_time);
  439. }
  440.  
  441. /*
  442.  * Log this port scan unless we're being flooded.
  443.  */
  444. void safe_log(struct host *info)
  445. {
  446.     static clock_t last = 0;
  447.     static int count = 0;
  448.     clock_t now;
  449.  
  450.     now = info->timestamp;
  451.     if (now - last > LOG_DELAY_THRESHOLD || now < last) count = 0;
  452.     if (++count <= LOG_COUNT_THRESHOLD + 1) last = now;
  453.  
  454.     if (count <= LOG_COUNT_THRESHOLD) {
  455.         do_log(info);
  456.     } else if (count == LOG_COUNT_THRESHOLD + 1) {
  457.         syslog(SYSLOG_LEVEL, "More possible port scans follow.\n");
  458.     }
  459. }
  460.  
  461. /*
  462.  * Process a TCP packet.
  463.  */
  464. void process_packet(struct header *packet, int size)
  465. {
  466.     struct ip *ip;
  467.     struct tcphdr *tcp;
  468.     struct in_addr addr;
  469.     unsigned short port;
  470.     unsigned char flags;
  471.     struct tms buf;
  472.     clock_t now;
  473.     struct host *current, *last, **head;
  474.     int hash, index, count;
  475.  
  476. /* Get the IP and TCP headers */
  477.     ip = &packet->ip;
  478.     tcp = (struct tcphdr *)((char *)packet + ((int)ip->ip_hl << 2));
  479.  
  480. /* Sanity check */
  481.     if ((char *)tcp + sizeof(struct tcphdr) > (char *)packet + size)
  482.         return;
  483.  
  484. /* Get the source address, destination port, and TCP flags */
  485.     addr = ip->ip_src;
  486.     port = tcp->th_dport;
  487.     flags = tcp->th_flags;
  488.  
  489. /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
  490.  * them spoof us. */
  491.     if (!addr.s_addr) return;
  492.  
  493. /* Use times(2) here not to depend on someone setting the time while we're
  494.  * running; we need to be careful with possible return value overflows. */
  495.     now = times(&buf);
  496.  
  497. /* Do we know this source address already? */
  498.     count = 0;
  499.     last = NULL;
  500.     if ((current = *(head = &state.hash[hash = hashfunc(addr)])))
  501.     do {
  502.         if (current->saddr.s_addr == addr.s_addr) break;
  503.         count++;
  504.         if (current->next) last = current;
  505.     } while ((current = current->next));
  506.  
  507. /* We know this address, and the entry isn't too old. Update it. */
  508.     if (current)
  509.     if (now - current->timestamp <= SCAN_DELAY_THRESHOLD &&
  510.         now >= current->timestamp) {
  511. /* Just update the TCP flags if we've seen this port already */
  512.         for (index = 0; index < current->count; index++)
  513.         if (current->ports[index] == port) {
  514.             current->flags_or |= flags;
  515.             current->flags_and &= flags;
  516.             return;
  517.         }
  518.  
  519. /* ACK to a new port? This could be an outgoing connection. */
  520.         if (flags & TH_ACK) return;
  521.  
  522. /* Packet to a new port, and not ACK: update the timestamp */
  523.         current->timestamp = now;
  524.  
  525. /* Logged this scan already? Then leave. */
  526.         if (current->count == SCAN_COUNT_THRESHOLD) return;
  527.  
  528. /* Update the TCP flags */
  529.         current->flags_or |= flags;
  530.         current->flags_and &= flags;
  531.  
  532. /* Zero out the destination address, source port and TTL if not fixed. */
  533.         if (current->daddr.s_addr != ip->ip_dst.s_addr)
  534.             current->daddr.s_addr = 0;
  535.         if (current->sport != tcp->th_sport)
  536.             current->sport = 0;
  537.         if (current->ttl != ip->ip_ttl)
  538.             current->ttl = 0;
  539.  
  540. /* Got enough destination ports to decide that this is a scan? Then log it. */
  541.         if (current->count == SCAN_COUNT_THRESHOLD - 1) {
  542.             safe_log(current);
  543.             current->count++;
  544.             return;
  545.         }
  546.  
  547. /* Remember the new port */
  548.         current->ports[current->count++] = port;
  549.  
  550.         return;
  551.     }
  552.  
  553. /* We know this address, but the entry is outdated. Mark it unused, and
  554.  * remove from the hash table. We'll allocate a new entry instead since
  555.  * this one might get re-used too soon. */
  556.     if (current) {
  557.         current->saddr.s_addr = 0;
  558.  
  559.         if (last)
  560.             last->next = last->next->next;
  561.         else if (*head)
  562.             *head = (*head)->next;
  563.         last = NULL;
  564.     }
  565.  
  566. /* We don't need an ACK from a new source address */
  567.     if (flags & TH_ACK) return;
  568.  
  569. /* Got too many source addresses with the same hash value? Then remove the
  570.  * oldest one from the hash table, so that they can't take too much of our
  571.  * CPU time even with carefully chosen spoofed IP addresses. */
  572.     if (count >= HASH_MAX && last) last->next = NULL;
  573.  
  574. /* We're going to re-use the oldest list entry, so remove it from the hash
  575.  * table first (if it is really already in use, and isn't removed from the
  576.  * hash table already because of the HASH_MAX check above). */
  577.  
  578. /* First, find it */
  579.     if (state.list[state.index].saddr.s_addr)
  580.         head = &state.hash[hashfunc(state.list[state.index].saddr)];
  581.     else
  582.         head = &last;
  583.     last = NULL;
  584.     if ((current = *head))
  585.     do {
  586.         if (current == &state.list[state.index]) break;
  587.         last = current;
  588.     } while ((current = current->next));
  589.  
  590. /* Then, remove it */
  591.     if (current) {
  592.         if (last)
  593.             last->next = last->next->next;
  594.         else if (*head)
  595.             *head = (*head)->next;
  596.     }
  597.  
  598. /* Get our list entry */
  599.     current = &state.list[state.index++];
  600.     if (state.index >= LIST_SIZE) state.index = 0;
  601.  
  602. /* Link it into the hash table */
  603.     head = &state.hash[hash];
  604.     current->next = *head;
  605.     *head = current;
  606.  
  607. /* And fill in the fields */
  608.     current->timestamp = now;
  609.     current->start = time(NULL);
  610.     current->saddr = addr;
  611.     current->daddr = ip->ip_dst;
  612.     current->sport = tcp->th_sport;
  613.     current->count = 1;
  614.     current->ports[0] = port;
  615.     current->flags_or = current->flags_and = flags;
  616.     current->ttl = ip->ip_ttl;
  617. }
  618.  
  619. /*
  620.  * Hmm, what could this be?
  621.  */
  622. int main()
  623. {
  624.     int raw, size;
  625.     struct header packet;
  626.  
  627. /* Get a raw socket. We could drop root right after that. */
  628.     if ((raw = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
  629.         perror("socket");
  630.         return 1;
  631.     }
  632.  
  633. /* Become a daemon */
  634.     switch (fork()) {
  635.     case -1:
  636.         perror("fork");
  637.         return 1;
  638.  
  639.     case 0:
  640.         break;
  641.  
  642.     default:
  643.         return 0;
  644.     }
  645.  
  646.     signal(SIGHUP, SIG_IGN);
  647.  
  648. /* Initialize the state. All source IP addresses are set to 0.0.0.0, which
  649.  * means the list entries aren't in use yet. */
  650.     memset(&state, 0, sizeof(state));
  651.  
  652. /* Huh? */
  653.     openlog(SYSLOG_IDENT, 0, SYSLOG_FACILITY);
  654.  
  655. /* Let's start */
  656.     while (1)
  657.     if ((size = read(raw, &packet, sizeof(packet))) >= sizeof(packet.ip))
  658.         process_packet(&packet, size);
  659. }
  660. <-->
  661.